package com.zhongyewx.teachercert.utils;

import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import com.zhongyewx.teachercert.api.ZYConstants;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public final class ZYLog {

    public static final String TAG = "ZYLog";

    public static final int MAX_SIZE = 1 * 512 * 1024;

    public static final String DATE_FORMAT = "MM-dd HH:mm:ss";

    public static final int LEVEL_TRACE = 0;
    public static final int LEVEL_WARNING = 1;
    public static final int LEVEL_ERROR = 2;
    public static final int LEVEL_KEYPATH = 3;
    public static final int LEVEL_NO_LOG = 4;

    private static int LOG_LEVEL = LEVEL_TRACE;

    private static final String LOG_NAME = "ZYWXTC.log";
    private static final String LOG_BACKUP_NAME = "ZYWXTC-Bak.log";

    private static final SimpleDateFormat SDF = new SimpleDateFormat(DATE_FORMAT);

    private static String mZipFileName;

    private static File mFile;
    private static FileWriter mFileWriter;
    private static BufferedWriter mBufferedWriter;

    private static String getLogPath() {
        String storagePath = ZYSDCardUtils.getExternalStoragePath();
        if (TextUtils.isEmpty(storagePath)) {
            Log.e(TAG, "storagePath is invalid!");
            return "";
        }

        String logPath = storagePath + File.separator + ZYConstants.APP_ROOT_DIRECTORY
                + File.separator + ZYConstants.APP_LOG_DIRECTORY;

        return logPath;
    }

    public static void init() {
        String logPath = getLogPath();
        if (TextUtils.isEmpty(logPath)) {
            Log.e(TAG, "init failed!");
        }

        if(!ZYSDCardUtils.checkDirectory(logPath)){
            return;
        }

        String newLog = logPath + File.separator + LOG_NAME;
        String bakLog = logPath + File.separator + LOG_BACKUP_NAME;

        destroy();

        Boolean isWriteHeader = false;
        try {
            mFile = new File(newLog);
            if (!mFile.exists()) {
                mFile.createNewFile();
                isWriteHeader = true;
            } else {
                if (mFile.length() >= MAX_SIZE) {
                    File bakFile = new File(bakLog);
                    if (bakFile.exists())
                        bakFile.delete();
                    mFile.renameTo(bakFile);
                    mFile = null;
                    mFile = new File(newLog);
                    mFile.createNewFile();
                    isWriteHeader = true;
                }
            }

            mFileWriter = new FileWriter(mFile, true);
            mBufferedWriter = new BufferedWriter(mFileWriter);

            if (isWriteHeader) {
                trace(TAG, getHeaderInfo());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static void destroy() {
        try {
            mFile = null;
            if (mFileWriter != null) {
                mFileWriter.close();
                mFileWriter = null;
            }
            if (mBufferedWriter != null) {
                mBufferedWriter.close();
                mBufferedWriter = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String getExceptionStactTrace(Exception e) {
        if (null == e)
            return null;

        StringBuilder ret = new StringBuilder();
        StackTraceElement[] stack = e.getStackTrace();
        for (int i = 0; stack != null && i < stack.length; ++i) {
            ret.append("\n").append(stack[i].toString());
        }
        return ret.toString();
    }

    public static void printExceptionStackTrace(Exception e) {
        if (e == null)
            return;

        error("Exception", "Exception: " + e.toString());
        StackTraceElement[] stack = e.getStackTrace();
        for (int i = 0; stack != null && i < stack.length; ++i) {
            error("Exception", stack[i].toString());
        }
    }

    private static void appendLog(String content, String level) {
        if (mBufferedWriter == null) {
            Log.e(TAG, "mBufferedWriter is null");
            return;
        }

        StringBuilder sb = new StringBuilder();
        sb.append(SDF.format(new Date())).append("\t ").append(level).append("\t")
                .append(Thread.currentThread().getId()).append("\t").append(content).append("\r\n");
        try {
            mBufferedWriter.write(sb.toString());
            mBufferedWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (mFile != null && mFile.length() >= MAX_SIZE) {
                init();
            }
        }
    }

    public static void error(String tag, String content) {
        if (LOG_LEVEL > LEVEL_ERROR) {
            return;
        }

        Log.e(tag, Thread.currentThread().getId() + "  " + content);
        appendLog(tag + "\t" + content, "e");
    }

    public static void warn(String tag, String content) {
        if (LOG_LEVEL > LEVEL_WARNING) {
            return;
        }

        Log.w(tag, Thread.currentThread().getId() + "  " + content);
        appendLog(tag + "\t" + content, "w");
    }

    public static void trace(String tag, String content) {
        if (LOG_LEVEL > LEVEL_TRACE) {
            return;
        }

        Log.i(tag, Thread.currentThread().getId() + "  " + content);
        appendLog(tag + "\t" + content, "i");
    }

    private static void setPriority(int priority) {
        LOG_LEVEL = priority;
    }

    public static int getPriority() {
        return LOG_LEVEL;
    }

    public static boolean openLog(int level) {
        if (level >= LEVEL_NO_LOG || level < LEVEL_TRACE) {
            return false;
        }

        setPriority(level);

        return true;
    }

    public static void closeLog() {
        setPriority(LEVEL_ERROR);
    }

    private static String getHeaderInfo() {
        String result = Build.MODEL + "-" + Build.VERSION.RELEASE;
        return result;
    }

    public static String zipLogFiles() {
        String logPath = getLogPath();
        if (TextUtils.isEmpty(logPath)) {
            ZYLog.error(TAG, "zipLogFiles | logPath is invalid!");
            return "";
        }

        if (!TextUtils.isEmpty(mZipFileName)) {
            File file = new File(mZipFileName);
            if (file.exists()) {
                file.delete();
            }
        }

        mZipFileName = logPath + File.separator + "中业log";

        String dumpFileList[] = { logPath + File.separator + LOG_NAME,
                logPath + File.separator + LOG_BACKUP_NAME };

        try {
            ZYLog.trace(TAG, "zip log attach start");

            File zipFile = new File(mZipFileName);
            ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(
                    new FileOutputStream(zipFile)));
            int readLen = 1024 * 4;
            byte[] bytes = new byte[readLen];

            for (int i = 0; i < dumpFileList.length; i++) {
                FileInputStream inputFile = null;
                String inputName = "";
                try {
                    if (dumpFileList[i] == null || dumpFileList[i].isEmpty()) {
                        continue;
                    }
                    File tmpFile = new File(dumpFileList[i]);
                    inputName = tmpFile.getName();
                    inputFile = new FileInputStream(tmpFile);
                } catch (Exception e) {
                    printExceptionStackTrace(e);
                    continue;
                }

                ZipEntry entry = new ZipEntry(inputName);
                zos.putNextEntry(entry);
                int len = inputFile.read(bytes, 0, readLen);
                while (len != -1) {
                    zos.write(bytes, 0, len);
                    len = inputFile.read(bytes, 0, readLen);
                }
                inputFile.close();
                zos.closeEntry();
            }
            zos.close();

            ZYLog.trace(TAG, "zip end: feedback attach length: " + zipFile.length());

            // if (zipFile.length() > (2 * 1000 * 1000))
            // return "";
        } catch (Exception e) {
            printExceptionStackTrace(e);
            return "";
        }

        return mZipFileName;
    }

}
